using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MediatR;
using RBAC.Domain.BomManage;
using RBAC.ErrorCode;
using RBAC.Read.Api.Application.Command.BomCommand;
using RBAC.Read.Api.Application.Dto.Bom;
using RBAC.Read.Api.Application.Services;
using Microsoft.Extensions.Logging;
using System.Linq;
using System.Collections.Generic;

namespace RBAC.Read.Api.Controllers.WmzBom
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    

    public class BomController : ControllerBase
    {
        private readonly IMediator mediator;
        private readonly IWeatherService _weather;
        private readonly IRiskEngine _risk;
        private readonly ILogger<BomController> _logger;

        public BomController(IMediator mediator, IWeatherService weather, IRiskEngine risk, ILogger<BomController> logger)
        {
            this.mediator = mediator;
            _weather = weather;
            _risk = risk;
            _logger = logger;
        }
        #region 产品接口
        //产品分页接口
        /// <summary>
        /// 获取产品分页列表（无筛选条件）
        /// </summary>
        [HttpGet]
        public Task<APIPaging<Product>> GetProductPage([FromQuery] GetProductPageCommand request, CancellationToken cancellationToken)
        {
            return mediator.Send(request, cancellationToken);
        }

        //产品详情
        /// <summary>
        /// 获取产品详情（按Id） 
        /// </summary>
        [HttpGet("{id:long}")]
        public Task<APIResult<Product>> GetProductDetailById([FromRoute] long id, CancellationToken cancellationToken)
        {
            var request = new GetProductDetailByIdCommand { Id = id };
            return mediator.Send(request, cancellationToken);
        }

        //产品导出
        /// <summary>
        /// 产品导出（.xlsx，无筛选条件）
        /// </summary>
        [Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/json")]
        [HttpGet]
        public async Task<IActionResult> GetProductExport([FromQuery] GetProductExportCommand request, CancellationToken cancellationToken)
        {
            var result = await mediator.Send(request, cancellationToken);
            if (result.Bytes == null || result.Bytes.Length == 0)
            {
                // 统一错误返回风格，使用 APIResult 包装
                var api = new APIResult<string>
                {
                    Code = APIEnums.Fail,
                    Msg = "导出失败或无数据",
                    Data = string.Empty
                };
                return Ok(api);
            }
            // 使用最初的文件命名与返回方式
            return File(result.Bytes, result.ContentType, result.FileName);
        }

        #endregion

        #region Bom接口
        /// <summary>
        /// 获取BOM分页列表（无筛选条件）
        /// </summary>
        [HttpGet]
        public Task<APIPaging<BomListItemDto>> GetBomList([FromQuery] GetBomListCommand request, CancellationToken cancellationToken)
        {
            return mediator.Send(request, cancellationToken);
        }

        /// <summary>
        /// 获取BOM详情（按Id）
        /// </summary>
        [HttpGet("{id:long}")]
        public Task<APIResult<BomDetailDto>> GetBomDetailById([FromRoute] long id, CancellationToken cancellationToken)
        {
            var request = new GetBomDetailByIdCommand { Id = id };
            return mediator.Send(request, cancellationToken);
        }



        #endregion

        #region Bom明细接口
        /// <summary>
        /// 按BomId获取BOM明细树形结构
        /// </summary>
        [HttpGet("{bomId:long}")]
        public Task<APIResult<List<BomItemTreeDto>>> GetBomItemTreeByBomId([FromRoute] long bomId, CancellationToken cancellationToken)
        {
            var request = new GetBomItemTreeByBomIdCommand { BomId = bomId };
            return mediator.Send(request, cancellationToken);
        }

        /// <summary>
        /// 根据BomId导出BomItem节点
        /// </summary>
        /// <param name="bomId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        [HttpGet("{bomId:long}")]
        public async Task<IActionResult> GetBomItemExportByBomId([FromRoute] long bomId, CancellationToken cancellationToken)
        {
            var request = new GetBomItemExportByBomIdCommand { BomId = bomId };
            var result = await mediator.Send(request, cancellationToken);
            if (string.Equals(result.FileName, "NOT_FOUND", System.StringComparison.Ordinal))
            {
                var notFoundApi = new APIResult<string>
                {
                    Code = APIEnums.Fail,
                    Msg = "未找到对应的BOM",
                    Data = string.Empty
                };
                return Ok(notFoundApi);
            }
            if (result.Bytes == null || result.Bytes.Length == 0)
            {
                var api = new APIResult<string>
                {
                    Code = APIEnums.Fail,
                    Msg = "导出失败或无数据",
                    Data = string.Empty
                };
                return Ok(api);
            }
            return File(result.Bytes, result.ContentType, result.FileName);
        }


        #endregion

        #region 天气相关接口
        /// <summary>
        /// 获取当前天气。
        /// 支持以 <c>city</c>（城市名）或 <c>lat/lon</c>（经纬度）指定位置。
        /// 示例：GET api/bom/getcurrent?city=Shanghai
        /// </summary>
        /// <param name="lat">纬度（与 lon 一起提供）</param>
        /// <param name="lon">经度（与 lat 一起提供）</param>
        /// <param name="city">城市名称（提供此参数时可不传 lat/lon）</param>
        /// <param name="units">单位：metric/imperial，默认 metric</param>
        [HttpGet]
        public async Task<IActionResult> GetCurrent([FromQuery] double? lat, [FromQuery] double? lon, [FromQuery] string? city, [FromQuery] string units = "metric")
        {
            if ((!lat.HasValue || !lon.HasValue) && !string.IsNullOrWhiteSpace(city))
            {
                var loc = await _weather.ResolveCityAsync(city!);
                lat = loc.Lat; lon = loc.Lon;
            }
            if (!lat.HasValue || !lon.HasValue)
            {
                return BadRequest("lat/lon 或 city 至少提供一个");
            }
            var data = await _weather.GetCurrentAsync(lat.Value, lon.Value, units);
            return Ok(data);
        }

        /// <summary>
        /// 获取小时级预报（固定返回未来 72 小时，每小时一个点）。
        /// 支持以 <c>city</c>（城市名）或 <c>lat/lon</c>（经纬度）指定位置。
        /// 示例：GET api/bom/getforecast?lat=31.23&lon=121.47
        /// </summary>
        /// <param name="lat">纬度</param>
        /// <param name="lon">经度</param>
        /// <param name="city">城市名称</param>
        /// <param name="units">单位：metric/imperial，默认 metric</param>
        [HttpGet]
        public async Task<IActionResult> GetForecast([FromQuery] double? lat, [FromQuery] double? lon, [FromQuery] string? city, [FromQuery] string units = "metric")
        {
            if ((!lat.HasValue || !lon.HasValue) && !string.IsNullOrWhiteSpace(city))
            {
                var loc = await _weather.ResolveCityAsync(city!);
                lat = loc.Lat; lon = loc.Lon;
            }
            if (!lat.HasValue || !lon.HasValue)
            {
                return BadRequest("lat/lon 或 city 至少提供一个");
            }
            const int fixedHours = 72;
            var data = await _weather.GetForecastAsync(lat.Value, lon.Value, fixedHours, units);
            return Ok(data);
        }

        /// <summary>
        /// V2：根据城市动态获取“当前天气 + 未来72小时预报”，评估规则并返回 6 条数据：
        /// 1 条天气信息（Type=weather）+ 5 条岗位预警（Type=role）。
        /// </summary>
        /// <param name="city">城市名称（必填）</param>
        /// <returns>六条 WeatherRoleItemDto</returns>
        [HttpGet]
        //[ActionName("EvaluateBycity")]
        //[Produces("application/json")]
        //[ProducesResponseType(typeof(List<WeatherRoleItemDto>), StatusCodes.Status200OK)]
        //[ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> EvaluateBycity([FromQuery] string? city, [FromQuery] string? lang = null)
        {
            if (string.IsNullOrWhiteSpace(city))
                return BadRequest("city 为必填参数");

            var loc = await _weather.ResolveCityAsync(city!);
            const int hours = 72; const string units = "metric";
            var current = await _weather.GetCurrentAsync(loc.Lat, loc.Lon, units);
            var forecast = await _weather.GetForecastAsync(loc.Lat, loc.Lon, hours, units);

            // 规则保持一致
            var rules = new List<RiskRuleDto>
            {
                new RiskRuleDto { Id = "r1", Metric = "temp",       Op = "gt",  Value = 35,  WindowHours = 6,  Advice = "高温预警：注意降温和设备散热", Severity = "high" },
                new RiskRuleDto { Id = "r2", Metric = "wind_speed", Op = "gte", Value = 10,  WindowHours = 3,  Advice = "大风风险：检查露天物料与围挡", Severity = "medium" },
                new RiskRuleDto { Id = "r3", Metric = "rain",       Op = "gt",  Value = 0.5, WindowHours = 12, Advice = "降雨风险：做好排水与防水",   Severity = "medium" },
                new RiskRuleDto { Id = "r4", Metric = "pop",        Op = "gte", Value = 0.6, WindowHours = 12, Advice = "高降水概率：调整室外工序", Severity = "medium" }
            };
            var eval = _risk.Evaluate(forecast, rules);

            // 生成第一条：天气信息
            var list = new List<WeatherRoleItemDto>();
            bool isEn = (lang ?? string.Empty).Trim().StartsWith("en", StringComparison.OrdinalIgnoreCase);
            // 当前天气项
            var weatherTitle = isEn ? $"{city} Current Weather" : $"{city} 当前天气";
            // 将中文天气主类映射回英文（仅用于展示）。WeatherService 内部是英->中的映射，这里做一个反向映射以便英文模式显示。
            var zh2en = new Dictionary<string, string>
            {
                ["雷暴"] = "Thunderstorm",
                ["毛毛雨"] = "Drizzle",
                ["雨"] = "Rain",
                ["雪"] = "Snow",
                ["薄雾"] = "Mist",
                ["烟雾"] = "Smoke",
                ["霾"] = "Haze",
                ["扬尘"] = "Dust",
                ["雾"] = "Fog",
                ["沙尘"] = "Sand",
                ["火山灰"] = "Ash",
                ["飑"] = "Squall",
                ["龙卷风"] = "Tornado",
                ["晴"] = "Clear",
                ["多云"] = "Clouds"
            };
            string weatherMainDisplay = isEn && !string.IsNullOrWhiteSpace(current.WeatherMain) && zh2en.TryGetValue(current.WeatherMain!, out var enVal)
                ? enVal
                : current.WeatherMain;
            list.Add(new WeatherRoleItemDto
            {
                Type = "weather",
                Title = weatherTitle,
                Temp = current.Temp,
                Humidity = current.Humidity,
                WindSpeed = current.WindSpeed,
                WeatherMain = weatherMainDisplay,
                GeneratedAt = DateTime.Now
            });

            // 基于命中指标生成五个岗位的风险预警
            var metricsMatched = new HashSet<string>(eval.Results.Where(r => r.Matched && !string.IsNullOrWhiteSpace(r.MetricZh)).Select(r => r.MetricZh!));
            string RoleSeverity(params string[] relatedMetrics)
            {
                bool anyHigh = eval.Results.Any(r => r.Matched && r.Severity == "高" && r.MetricZh != null && relatedMetrics.Contains(r.MetricZh));
                bool anyMatch = eval.Results.Any(r => r.Matched && r.MetricZh != null && relatedMetrics.Contains(r.MetricZh));
                return anyHigh ? "高" : (anyMatch ? "中" : "低");
            }
            string affected = isEn ? $"Next {hours} hours" : $"未来{hours}小时";

            // 未命中时的通用建议：依据当前天气主类给出基础安全提示
            List<string> DefaultMeasures(string role, string? weatherMain)
            {
                var wsRaw = (weatherMain ?? string.Empty).ToLowerInvariant();
                bool isRain = wsRaw.Contains("雨") || wsRaw.Contains("drizzle") || wsRaw.Contains("rain") || wsRaw.Contains("thunder");
                bool isFog = wsRaw.Contains("雾") || wsRaw.Contains("霾") || wsRaw.Contains("薄雾") || wsRaw.Contains("fog") || wsRaw.Contains("mist") || wsRaw.Contains("haze");
                bool isSnow = wsRaw.Contains("雪") || wsRaw.Contains("snow");
                var tips = new List<string>();
                if (isRain)
                {
                    if (isEn)
                    {
                        if (role == "户外作业") tips.AddRange(new[]{"Anti-slip and rain protection","Reschedule moisture-sensitive tasks","Set temporary drainage"});
                        else if (role == "设备耐温") tips.AddRange(new[]{"Check waterproofing of electrical cabinets","Suspend outdoor live operations"});
                        else if (role == "物流运输") tips.AddRange(new[]{"Bypass flooded sections","Reduce speed and increase distance"});
                        else if (role == "人员安全") tips.AddRange(new[]{"Pre-shift rain risk briefing","Floor anti-slip reminders"});
                        else if (role == "库存管理") tips.AddRange(new[]{"Inspect for leaks at doors/windows","Moisture protection for hygroscopic materials"});
                    }
                    else
                    {
                        if (role == "户外作业") tips.AddRange(new[]{"雨天防滑与防护","湿敏工序调整","设置临时排水"});
                        else if (role == "设备耐温") tips.AddRange(new[]{"电柜防水检查","室外带电作业暂停"});
                        else if (role == "物流运输") tips.AddRange(new[]{"涉水路段绕行","控速增距"});
                        else if (role == "人员安全") tips.AddRange(new[]{"班前雨天风险告知","地面防滑提示"});
                        else if (role == "库存管理") tips.AddRange(new[]{"仓库门窗渗漏排查","湿敏物料防潮覆盖"});
                    }
                }
                else if (isFog)
                {
                    if (isEn)
                    {
                        if (role == "户外作业") tips.AddRange(new[]{"Enhanced supervision under low visibility","Suspend high-risk tasks if needed"});
                        else if (role == "物流运输") tips.AddRange(new[]{"Slow down with lights on","Avoid long-distance night driving"});
                        else tips.Add("Ensure PPE and visual signage");
                    }
                    else
                    {
                        if (role == "户外作业") tips.AddRange(new[]{"低能见度作业加强监护","必要时暂停高风险作业"});
                        else if (role == "物流运输") tips.AddRange(new[]{"低能见度控速开灯","避免夜间长途"});
                        else tips.Add("做好个体防护与可视化标识");
                    }
                }
                else if (isSnow)
                {
                    if (isEn)
                    {
                        if (role == "户外作业") tips.AddRange(new[]{"Snow removal and anti-slip","Suspend work at height"});
                        else if (role == "物流运输") tips.AddRange(new[]{"Install snow chains","Drive slowly and keep distance"});
                        else if (role == "人员安全") tips.Add("Anti-slip warnings on walkways and stairs");
                        else if (role == "库存管理") tips.Add("Clear snow at warehouse entrances and ramps promptly");
                    }
                    else
                    {
                        if (role == "户外作业") tips.AddRange(new[]{"除雪防滑","高处作业暂停"});
                        else if (role == "物流运输") tips.AddRange(new[]{"装防滑链","慢行控距"});
                        else if (role == "人员安全") tips.Add("行走与梯步防滑警示");
                        else if (role == "库存管理") tips.Add("库区门口与坡道及时除雪防滑");
                    }
                }
                else // 晴、多云等
                {
                    if (isEn)
                    {
                        if (role == "户外作业") tips.AddRange(new[]{"Hydration and sun protection","Plan reasonable work intensity"});
                        else if (role == "设备耐温") tips.AddRange(new[]{"Check cooling and ventilation","Monitor key equipment temperature"});
                        else if (role == "物流运输") tips.AddRange(new[]{"Vehicle checks (tires/brakes/cooling)","Plan loading/unloading time windows"});
                        else if (role == "人员安全") tips.Add("Pre-shift safety briefing and PPE");
                        else if (role == "库存管理") tips.Add("Routine temperature and humidity inspections");
                    }
                    else
                    {
                        if (role == "户外作业") tips.AddRange(new[]{"做好补水与防晒","合理安排作业强度"});
                        else if (role == "设备耐温") tips.AddRange(new[]{"检查散热通风","关注关键设备温升"});
                        else if (role == "物流运输") tips.AddRange(new[]{"车辆例检（轮胎/制动/冷却）","合理规划装卸时段"});
                        else if (role == "人员安全") tips.Add("班前安全提醒与PPE佩戴");
                        else if (role == "库存管理") tips.Add("温湿度常规巡检与记录");
                    }
                }
                return tips;
            }

            string LocRole(string zh)
            {
                if (!isEn) return zh;
                return zh switch
                {
                    "户外作业" => "Outdoor Work",
                    "设备耐温" => "Equipment Thermal Tolerance",
                    "物流运输" => "Logistics & Transportation",
                    "人员安全" => "Personnel Safety",
                    "库存管理" => "Inventory Management",
                    _ => zh
                };
            }

            string LocSeverity(string zh)
            {
                if (!isEn) return zh;
                return zh switch { "高" => "High", "中" => "Medium", _ => "Low" };
            }

            WeatherRoleItemDto MakeRole(string role, string severity, IEnumerable<string> measures)
            {
                return new WeatherRoleItemDto
                {
                    Type = "role",
                    Title = LocRole(role),
                    Severity = LocSeverity(severity),
                    Measures = measures.ToList(),
                    Affected = affected,
                    GeneratedAt = DateTime.Now
                };
            }

            // 1) 户外作业
            {
                var sev = RoleSeverity("温度", "风速", "降雨量", "降水概率");
                var measures = new List<string>();
                if (metricsMatched.Contains("温度")) measures.AddRange(isEn ? new[] { "Avoid 11:00–16:00 heat exposure; rotate crews; provide shade and hydration" } : new[] { "避开11:00–16:00高温时段", "缩短连续作业并轮换", "设置遮阳与补水点" });
                if (metricsMatched.Contains("风速")) measures.AddRange(isEn ? new[] { "Suspend height/edge/lifting work; reinforce scaffolds and barriers" } : new[] { "暂停高空/临边/吊装作业", "脚手与围挡加固" });
                if (metricsMatched.Contains("降雨量") || metricsMatched.Contains("降水概率")) measures.AddRange(isEn ? new[] { "Adjust moisture-sensitive tasks; prepare tarps and temporary drainage" } : new[] { "湿敏工序调整", "备好防水布与临时排水" });
                if (measures.Count == 0) measures.AddRange(DefaultMeasures("户外作业", current.WeatherMain));
                list.Add(MakeRole("户外作业", sev, measures));
            }

            // 2) 设备耐温
            {
                var sev = RoleSeverity("温度", "降雨量", "降水概率", "湿度");
                var measures = new List<string>();
                if (metricsMatched.Contains("温度")) measures.AddRange(isEn ? new[] { "Check heat dissipation/air ducts/coolant; derate during hot periods" } : new[] { "检查散热/风道/冷却液", "高温时段降载运行" });
                if (metricsMatched.Contains("降雨量") || metricsMatched.Contains("降水概率")) measures.AddRange(isEn ? new[] { "Suspend outdoor live/open-cover operations; waterproof check for panels" } : new[] { "室外带电/开盖作业暂停", "电箱/机柜防水检查" });
                if (metricsMatched.Contains("湿度")) measures.Add(isEn ? "Inspect cabinet condensation; dehumidify if needed" : "电气柜冷凝排查，必要时除湿");
                if (measures.Count == 0) measures.AddRange(DefaultMeasures("设备耐温", current.WeatherMain));
                list.Add(MakeRole("设备耐温", sev, measures));
            }

            // 3) 物流运输
            {
                var sev = RoleSeverity("温度", "风速", "降雨量", "降水概率");
                var measures = new List<string>();
                if (metricsMatched.Contains("温度")) measures.AddRange(isEn ? new[] { "Check A/C cooling and tire temperature; avoid loading/unloading under heat" } : new[] { "检查空调制冷与轮胎温升", "避免高温暴晒装卸" });
                if (metricsMatched.Contains("风速")) measures.AddRange(isEn ? new[] { "Restrict or reschedule under strong winds; beware of bridges and viaducts" } : new[] { "强风时段限行或改期", "关注高架/桥梁/跨海路段" });
                if (metricsMatched.Contains("降雨量") || metricsMatched.Contains("降水概率")) measures.AddRange(isEn ? new[] { "Avoid heavy rain periods; detour flooded roads; slow down and keep distance" } : new[] { "避开强降雨时段", "涉水路段绕行，控速增距" });
                if (measures.Count == 0) measures.AddRange(DefaultMeasures("物流运输", current.WeatherMain));
                list.Add(MakeRole("物流运输", sev, measures));
            }

            // 4) 人员安全
            {
                var sev = RoleSeverity("温度", "风速", "降雨量", "降水概率");
                var measures = new List<string>();
                if (eval.Summary == "高")
                {
                    if (isEn) measures.AddRange(new[] { "Pre-shift safety briefing and risk notification", "Increase safety patrols and temporary cordons" });
                    else measures.AddRange(new[] { "班前安全提醒与风险告知", "增派安全巡检与临时警戒线" });
                }
                if (metricsMatched.Contains("温度")) measures.AddRange(isEn ? new[] { "Heat stress screening and care", "Set hydration and rest points" } : new[] { "防暑健康筛查与关怀", "设置补水点与休息点" });
                if (metricsMatched.Contains("风速")) measures.Add(isEn ? "Inspect stability of temporary structures/stockpiles" : "临时结构/堆放稳固巡查");
                if (metricsMatched.Contains("降雨量") || metricsMatched.Contains("降水概率")) measures.Add(isEn ? "Anti-slip reminders for walking and work in rain" : "雨天行走与作业防滑提醒");
                if (measures.Count == 0) measures.AddRange(DefaultMeasures("人员安全", current.WeatherMain));
                list.Add(MakeRole("人员安全", sev, measures));
            }

            // 5) 库存管理
            {
                var sev = RoleSeverity("温度", "降雨量", "降水概率", "湿度");
                var measures = new List<string>();
                if (metricsMatched.Contains("温度")) measures.AddRange(new[] { "温敏/易燃品温控", "仓库通风降温与温湿度监测" });
                if (metricsMatched.Contains("降雨量") || metricsMatched.Contains("降水概率")) measures.AddRange(new[] { "屋面门窗渗漏检查", "纸箱/粉料/电子件防潮覆盖" });
                if (metricsMatched.Contains("湿度")) measures.AddRange(new[] { "增加防潮剂与抽检频次", "启用除湿机并设定湿度预警" });
                if (measures.Count == 0) measures.AddRange(DefaultMeasures("库存管理", current.WeatherMain));
                list.Add(MakeRole("库存管理", sev, measures));
            }

            // 只返回前 6 条（1 + 5）
            return Ok(list.Take(6).ToList());
        }
        #endregion
    }
}
